<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SimpleTrace | Performance Insights</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  <style>
    :root {
      --primary: #6f42c1;
      --primary-light: #8a63d2;
      --secondary: #f8f9fa;
      --dark: #1a1a1a;
      --light: #ffffff;
      --gray: #6c757d;
      --gray-light: #e9ecef;
      --success: #28a745;
      --danger: #dc3545;
      --warning: #ffc107;
      --info: #17a2b8;
      --border-radius: 12px;
      --box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
      --transition: all 0.3s ease;
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Inter', sans-serif;
      background-color: #f5f7fa;
      color: var(--dark);
      line-height: 1.6;
      padding: 0;
      overflow-x: hidden;
    }

    .container {
      max-width: 1400px;
      margin: 30px auto;
      padding: 0 20px;
    }

    /* Header */
    header {
      background-color: var(--light);
      box-shadow: var(--box-shadow);
      padding: 1rem 0;
      position: sticky;
      top: 0;
      z-index: 100;
    }

    .header-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .logo {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .logo i {
      color: var(--primary);
      font-size: 1.8rem;
    }

    .logo h1 {
      font-size: 1.5rem;
      font-weight: 700;
      color: var(--dark);
    }

    .header-actions {
      display: flex;
      gap: 15px;
    }

    .btn {
      padding: 0.5rem 1rem;
      border-radius: var(--border-radius);
      font-weight: 500;
      cursor: pointer;
      transition: var(--transition);
      border: none;
      display: inline-flex;
      align-items: center;
      gap: 8px;
    }

    .btn-primary {
      background-color: var(--primary);
      color: var(--light);
    }

    .btn-primary:hover {
      background-color: var(--primary-light);
      transform: translateY(-2px);
    }

    .btn-outline {
      background-color: transparent;
      border: 1px solid var(--gray-light);
      color: var(--dark);
    }

    .btn-outline:hover {
      background-color: var(--gray-light);
    }

    /* Stats */
    .stats-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 1.5rem;
      margin-bottom: 2rem;
    }

    .stat-card {
      background-color: var(--light);
      border-radius: var(--border-radius);
      padding: 1.5rem;
      box-shadow: var(--box-shadow);
      text-align: center;
    }

    .stat-value {
      font-size: 2rem;
      font-weight: 700;
      color: var(--primary);
      margin-bottom: 0.5rem;
    }

    .stat-label {
      font-size: 0.9rem;
      color: var(--gray);
    }

    /* Search Bar */
    .search-bar {
      background-color: var(--light);
      padding: 1.5rem 0;
      border-bottom: 1px solid var(--gray-light);
    }

    .search-container {
      display: flex;
      gap: 10px;
      max-width: 800px;
      margin: 0 auto;
    }

    .search-input {
      flex: 1;
      padding: 0.75rem 1rem;
      border: 1px solid var(--gray-light);
      border-radius: var(--border-radius);
      font-size: 1rem;
      transition: var(--transition);
    }

    .search-input:focus {
      outline: none;
      border-color: var(--primary);
      box-shadow: 0 0 0 2px rgba(111, 66, 193, 0.2);
    }

    .search-btn {
      padding: 0.75rem 1.5rem;
    }

    .wrapper {
      display: flex;
      flex-direction: column;
      min-height: 72.9vh;
    }

    /* Main Content */
    main {
      padding: 0.4rem 0;
      flex: 1;
    }

    /* Card */
    .card {
      background-color: var(--light);
      border-radius: var(--border-radius);
      box-shadow: var(--box-shadow);
      overflow: hidden;
      transition: var(--transition);
      margin-bottom: 1.5rem;
    }

    .card:hover {
      box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
    }

    .card-header {
      padding: 1.2rem 1.5rem;
      border-bottom: 1px solid var(--gray-light);
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .card-title {
      font-size: 1.2rem;
      font-weight: 600;
      color: var(--dark);
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .card-title i {
      color: var(--primary);
    }

    .card-actions {
      display: flex;
      gap: 10px;
    }

    .card-body {
      padding: 1.5rem;
    }

    /* Table */
    .trace-table {
      width: 100%;
      border-collapse: collapse;
    }

    .trace-table th,
    .trace-table td {
      padding: 1rem;
      text-align: left;
      border-bottom: 1px solid var(--gray-light);
    }

    .trace-table th {
      font-weight: 600;
      color: var(--gray);
      text-transform: uppercase;
      font-size: 0.8rem;
      letter-spacing: 0.5px;
    }

    .trace-table tr:hover {
      background-color: rgba(111, 66, 193, 0.05);
    }

    .trace-table .method {
      display: inline-block;
      padding: 0.25rem 0.5rem;
      border-radius: 4px;
      font-size: 0.8rem;
      font-weight: 600;
      text-transform: uppercase;
    }

    .trace-table .method-get {
      background-color: rgba(40, 167, 69, 0.1);
      color: var(--success);
    }

    .trace-table .method-post {
      background-color: rgba(23, 162, 184, 0.1);
      color: var(--info);
    }

    .trace-table .method-put {
      background-color: rgba(255, 193, 7, 0.1);
      color: var(--warning);
    }

    .trace-table .method-delete {
      background-color: rgba(220, 53, 69, 0.1);
      color: var(--danger);
    }

    .trace-table .trace-link {
      color: var(--primary);
      text-decoration: none;
      font-weight: 500;
      transition: var(--transition);
    }

    .trace-table .trace-link:hover {
      color: var(--primary-light);
      text-decoration: underline;
    }

    /* Pagination */
    .pagination {
      display: flex;
      justify-content: center;
      align-items: center;
      gap: 10px;
      margin-top: 2rem;
    }

    .pagination-btn {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: var(--light);
      border: 1px solid var(--gray-light);
      cursor: pointer;
      transition: var(--transition);
    }

    .pagination-btn:hover {
      background-color: var(--gray-light);
    }

    .pagination-btn.active {
      background-color: var(--primary);
      color: var(--light);
      border-color: var(--primary);
    }

    /* Footer */
    footer {
      background-color: var(--dark);
      color: var(--light);
      padding: 2rem 0;
      bottom: 0px;
      width: 100%;
    }

    .footer-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .footer-links {
      display: flex;
      gap: 1.5rem;
    }

    .footer-links a {
      color: var(--light);
      text-decoration: none;
      transition: var(--transition);
    }

    .footer-links a:hover {
      color: var(--primary-light);
    }

    .copyright {
      font-size: 0.9rem;
      color: var(--gray);
    }

    /* Responsive */
    @media (max-width: 768px) {
      .header-content {
        flex-direction: column;
        gap: 1rem;
      }

      .stats-grid {
        grid-template-columns: 1fr;
      }

      .search-container {
        flex-direction: column;
      }

      .trace-table {
        display: block;
        overflow-x: auto;
      }

      .trace-table th,
      .trace-table td {
        white-space: nowrap;
      }
    }

    /* 排序指示器 */
    .sortable {
      cursor: pointer;
      position: relative;
      padding-right: 20px !important;
    }

    .sortable:hover {
      background-color: rgba(111, 66, 193, 0.1);
    }

    .sortable::after {
      content: "⇅";
      position: absolute;
      right: 8px;
      top: 50%;
      transform: translateY(-50%);
      font-size: 12px;
      opacity: 0.5;
    }

    .sortable.asc::after {
      content: "↑";
      opacity: 1;
    }

    .sortable.desc::after {
      content: "↓";
      opacity: 1;
    }

    /* 分页控件 */
    .pagination-controls {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-top: 1rem;
    }

    .page-size-selector {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .page-size-selector select {
      padding: 0.5rem;
      border-radius: var(--border-radius);
      border: 1px solid var(--gray-light);
    }

  </style>
</head>
<body>
  <header>
    <div class="container" style="margin: 0px auto;">
      <div class="header-content">
        <div class="logo">
          <i class="fas fa-project-diagram"></i>
          <h1>SimpleTrace</h1>
        </div>
        <div class="header-actions">
          <button class="btn btn-outline" id="exportBtn">
            <i class="fas fa-download"></i> Export
          </button>
          <button class="btn btn-primary">
            <i class="fas fa-cog"></i> Settings
          </button>
        </div>
      </div>
    </div>
  </header>

  <!-- 统计概览 -->
  <div class="container">
    <div class="stats-grid">
      <div class="stat-card">
        <div class="stat-value" id="total-traces">0</div>
        <div class="stat-label">Total Traces</div>
      </div>
      <div class="stat-card">
        <div class="stat-value" id="total-spans">0</div>
        <div class="stat-label">Total Spans</div>
      </div>
      <div class="stat-card">
        <div class="stat-value" id="memory-usage">0 B</div>
        <div class="stat-label">Memory Usage</div>
      </div>
      <div class="stat-card">
        <div class="stat-value" id="unique-urls">0</div>
        <div class="stat-label">Unique URLs</div>
      </div>
    </div>
  </div>

  <!-- 搜索栏 -->
  <div class="search-bar">
    <div class="container" style="margin: 0px auto;">
      <div class="search-container">
        <input type="text" 
               id="urlSearch" 
               class="search-input" 
               placeholder="Search by URL or method..."
               aria-label="Search Traces">
        <button id="searchBtn" class="btn btn-primary search-btn">
          <i class="fas fa-search"></i> Search
        </button>
      </div>
    </div>
  </div>
  <div class="wrapper">
    <main>
      <div class="container">
        <!-- 跟踪列表卡片 -->
        <div class="card">
          <div class="card-header">
            <h2 class="card-title">
              <i class="fas fa-list"></i> Trace List
            </h2>
            <div class="card-actions">
              <button class="btn btn-outline" id="refreshBtn">
                <i class="fas fa-sync-alt"></i> Refresh
              </button>
            </div>
          </div>
          <div class="card-body">
            <table class="trace-table">
              <thead>
                <tr>
                  <th class="sortable" data-sort="method">Method</th>
                  <th class="sortable" data-sort="url">URL</th>
                  <th class="sortable" data-sort="count">Count</th>
                  <th class="sortable" data-sort="avgSpans">Avg Spans</th>
                  <th class="sortable" data-sort="avgDuration">Avg Duration</th>
                  <th>Example Trace</th>
                  <th>Actions</th>
                </tr>
              </thead>
              <tbody id="traceTableBody">
                <!-- 数据将通过JavaScript动态填充 -->
              </tbody>
            </table>

            <!-- 增强的分页控件 -->
            <div class="pagination-controls">
              <div class="page-size-selector">
                <span>Items per page:</span>
                <select id="pageSize">
                  <option value="5">5</option>
                  <option value="10" selected>10</option>
                  <option value="20">20</option>
                  <option value="50">50</option>
                  <option value="100">100</option>
                </select>
              </div>
            
              <div class="pagination">
                <button class="pagination-btn" id="firstPage">
                  <i class="fas fa-angle-double-left"></i>
                </button>
                <button class="pagination-btn" id="prevPage">
                  <i class="fas fa-angle-left"></i>
                </button>
                <span id="pageInfo">Page 1 of 1</span>
                <button class="pagination-btn" id="nextPage">
                  <i class="fas fa-angle-right"></i>
                </button>
                <button class="pagination-btn" id="lastPage">
                  <i class="fas fa-angle-double-right"></i>
                </button>
              </div>
              </div>
              </div>
              </div>
              </div>
              </main>

    <footer>
      <div class="container" style="margin: 0px auto;">
        <div class="footer-content">
          <div class="logo">
            <i class="fas fa-project-diagram"></i>
            <h2>SimpleTrace</h2>
          </div>
          <div class="footer-links">
            <a href="#">Documentation</a>
            <a href="#">GitHub</a>
            <a href="#">Contact</a>
          </div>
          <div class="copyright">
            &copy; 2025 SimpleTrace by cg33. All rights reserved.
          </div>
        </div>
      </div>
    </footer>
  </div>

  <script>
    // 表格管理类
    class TableManager {
      constructor() {
        this.data = [];
        this.filteredData = [];
        this.currentPage = 1;
        this.pageSize = 10;
        this.sortColumn = null;
        this.sortDirection = 'asc';
        this.searchTerm = '';
        
        this.initElements();
        this.bindEvents();
        this.prepareData();
        this.renderTable();
      }
      
      initElements() {
        this.tableBody = document.getElementById('traceTableBody');
        this.pageSizeSelect = document.getElementById('pageSize');
        this.pageInfo = document.getElementById('pageInfo');
        this.firstPageBtn = document.getElementById('firstPage');
        this.prevPageBtn = document.getElementById('prevPage');
        this.nextPageBtn = document.getElementById('nextPage');
        this.lastPageBtn = document.getElementById('lastPage');
        this.searchInput = document.getElementById('urlSearch');
        this.sortableHeaders = document.querySelectorAll('.sortable');
      }
      
      bindEvents() {
        this.pageSizeSelect.addEventListener('change', () => {
          this.pageSize = parseInt(this.pageSizeSelect.value);
          this.currentPage = 1;
          this.renderTable();
        });
        
        this.firstPageBtn.addEventListener('click', () => {
          this.currentPage = 1;
          this.renderTable();
        });
        
        this.prevPageBtn.addEventListener('click', () => {
          if (this.currentPage > 1) {
            this.currentPage--;
            this.renderTable();
          }
        });
        
        this.nextPageBtn.addEventListener('click', () => {
          if (this.currentPage < this.totalPages) {
            this.currentPage++;
            this.renderTable();
          }
        });
        
        this.lastPageBtn.addEventListener('click', () => {
          this.currentPage = this.totalPages;
          this.renderTable();
        });
        
        this.searchInput.addEventListener('input', () => {
          this.searchTerm = this.searchInput.value.toLowerCase();
          this.currentPage = 1;
          this.filterData();
          this.renderTable();
        });
        
        this.sortableHeaders.forEach(header => {
          header.addEventListener('click', () => {
            const column = header.dataset.sort;
            
            if (this.sortColumn === column) {
              this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
            } else {
              this.sortColumn = column;
              this.sortDirection = 'asc';
            }
            
            // 更新排序指示器
            this.sortableHeaders.forEach(h => {
              h.classList.remove('asc', 'desc');
            });
            
            header.classList.add(this.sortDirection);
            
            this.sortData();
            this.renderTable();
          });
        });
      }
      
      prepareData() {
        this.data = Object.values(traceData.info.trace_by_urls).map(item => ({
          method: item.method,
          url: item.url,
          count: item.count,
          avgSpans: item.avg_span_count,
          avgDuration: item.avg_duration,
          traceExample: item.trace_example
        }));
        
        this.filteredData = [...this.data];
      }
      
      filterData() {
        if (!this.searchTerm) {
          this.filteredData = [...this.data];
          return;
        }
        
        this.filteredData = this.data.filter(item => {
          return (
            item.method.toLowerCase().includes(this.searchTerm) ||
            item.url.toLowerCase().includes(this.searchTerm) ||
            item.traceExample.toLowerCase().includes(this.searchTerm)
          );
        });
      }
      
      sortData() {
        if (!this.sortColumn) return;
        
        this.filteredData.sort((a, b) => {
          let valueA = a[this.sortColumn];
          let valueB = b[this.sortColumn];
          
          // 处理数字排序
          if (this.sortColumn === 'count' || this.sortColumn === 'avgSpans') {
            valueA = Number(valueA);
            valueB = Number(valueB);
          }
          
          // 处理持续时间排序 (去掉 " ms")
          if (this.sortColumn === 'avgDuration') {
            valueA = Number(valueA.replace(' ms', ''));
            valueB = Number(valueB.replace(' ms', ''));
          }
          
          if (valueA < valueB) {
            return this.sortDirection === 'asc' ? -1 : 1;
          }
          if (valueA > valueB) {
            return this.sortDirection === 'asc' ? 1 : -1;
          }
          return 0;
        });
      }
      
      renderTable() {
        // 计算分页数据
        this.totalItems = this.filteredData.length;
        this.totalPages = Math.ceil(this.totalItems / this.pageSize);
        
        // 计算当前页的数据范围
        const startIndex = (this.currentPage - 1) * this.pageSize;
        const endIndex = Math.min(startIndex + this.pageSize, this.totalItems);
        const pageData = this.filteredData.slice(startIndex, endIndex);
        
        // 渲染表格行
        this.tableBody.innerHTML = '';
        
        pageData.forEach(item => {
          const row = document.createElement('tr');
          
          // 方法列
          const methodCell = document.createElement('td');
          const methodSpan = document.createElement('span');
          methodSpan.className = `method method-${item.method.toLowerCase()}`;
          methodSpan.textContent = item.method;
          methodCell.appendChild(methodSpan);
          row.appendChild(methodCell);
          
          // URL列
          const urlCell = document.createElement('td');
          urlCell.textContent = item.url;
          row.appendChild(urlCell);
          
          // 计数列
          const countCell = document.createElement('td');
          countCell.textContent = item.count;
          row.appendChild(countCell);
          
          // 平均Span数列
          const spanCountCell = document.createElement('td');
          spanCountCell.textContent = item.avgSpans;
          row.appendChild(spanCountCell);
          
          // 平均持续时间列
          const durationCell = document.createElement('td');
          durationCell.textContent = item.avgDuration;
          row.appendChild(durationCell);
          
          // 示例Trace列
          const traceCell = document.createElement('td');
          const traceLink = document.createElement('a');
          // 跳转新标签页
          traceLink.target = '_blank';
          // 获取路由前缀，取当前页面url中 /api/v1 前面的部分
          let urlPrefix = window.location.href.split('/api/v1')[0];
          traceLink.href = `${urlPrefix}/api/v1/superadmin/devops/trace?trace_id=${item.traceExample}`;
          traceLink.className = 'trace-link';
          traceLink.textContent = item.traceExample;
          traceCell.appendChild(traceLink);
          row.appendChild(traceCell);
          
          // 操作列
          const actionsCell = document.createElement('td');
          const viewBtn = document.createElement('button');
          viewBtn.className = 'btn btn-outline';
          viewBtn.style.padding = '0.25rem 0.5rem';
          viewBtn.style.fontSize = '0.8rem';
          viewBtn.innerHTML = '<i class="fas fa-eye"></i> 火焰图';
          viewBtn.onclick = () => {
            window.open(`${urlPrefix}/api/v1/superadmin/devops/traceframe?trace_id=${item.traceExample}`, '_blank');
          };
          actionsCell.appendChild(viewBtn);
          row.appendChild(actionsCell);
          
          this.tableBody.appendChild(row);
        });
        
        // 更新分页信息
        this.updatePaginationControls();
      }
      
      updatePaginationControls() {
        // 更新页面信息
        this.pageInfo.textContent = `Page ${this.currentPage} of ${this.totalPages}`;
        
        // 启用/禁用分页按钮
        this.firstPageBtn.disabled = this.currentPage === 1;
        this.prevPageBtn.disabled = this.currentPage === 1;
        this.nextPageBtn.disabled = this.currentPage === this.totalPages || this.totalPages === 0;
        this.lastPageBtn.disabled = this.currentPage === this.totalPages || this.totalPages === 0;
      }
    }

    // 示例数据
    const traceData = {{.TraceInfo}};

    // 更新统计信息
    function updateStats() {
      document.getElementById('total-traces').textContent = traceData.info.total;
      document.getElementById('total-spans').textContent = traceData.info.total_span;
      document.getElementById('memory-usage').textContent = traceData.info.memory_usage;
      document.getElementById('unique-urls').textContent = Object.keys(traceData.info.trace_by_urls).length;
    }

    // 页面加载后初始化
    window.addEventListener('load', () => {
      // 初始化表格管理器
      new TableManager();

      updateStats();
      
      // 搜索功能
      document.getElementById('searchBtn').addEventListener('click', () => {
        const searchTerm = document.getElementById('urlSearch').value.toLowerCase();
        const rows = document.querySelectorAll('#traceTableBody tr');
        
        rows.forEach(row => {
          const url = row.cells[1].textContent.toLowerCase();
          const method = row.cells[0].textContent.toLowerCase();
          
          if (url.includes(searchTerm) || method.includes(searchTerm)) {
            row.style.display = '';
          } else {
            row.style.display = 'none';
          }
        });
      });
      
      // 刷新功能
      document.getElementById('refreshBtn').addEventListener('click', () => {
        // 刷新页面
        window.location.reload();
      });

      // 导出功能
      document.getElementById('exportBtn').addEventListener('click', () => {
        alert('Export functionality will be implemented here');
      });
    });
  </script>
</body>
</html>